package game
import (
	"github.com/name5566/leaf/log"
	"message"
	"math"
	"game/poker/hand"
	"utils"
	"github.com/golang/protobuf/proto"
)

//----------------------------------------游戏流程----------------------------------

// 更新庄家位置
func (self *Room) updateDealer() {
	var dealer *User
	if self.dealerSeat == -1 {
		// 随机取一个庄家
		dealer = self.getRandomPlayer()
	} else {
		// 庄家移动到下一个位置
		dealer = self.getNextPlayer(self.dealerSeat, nil)
	}

	// 选定庄家
	if dealer != nil {
		self.dealerSeat = dealer.seat
		self.broadcastAction(dealer, message.PokerAction_ACTION_DEALER, 0)
		log.Debug("更新庄家: %v %v", dealer.str(), self.dealerSeat)
	} else {
		log.Error("无法确定庄家")
	}
}

// 设置大小盲注
func (self *Room) updateBlindAnte() {
	// 下前注
	if self.ante > 0 {
		for _, v := range self.playersPlaying() {
			amount := int(math.Min(float64(self.ante), float64(v.money)))
			self.actionPlayerBet(v, amount)
		}
	}

	// 下盲注  小盲注为庄家的下一个，大盲注为小盲注的下一个
	sbPlayer := self.getNextPlayer(self.dealerSeat, nil)
	self.smallBlindSeat = sbPlayer.seat
	bbPlayer := self.getNextPlayer(sbPlayer.seat, nil)
	self.bigBlindSeat = bbPlayer.seat
	self.actionSmallBlind(sbPlayer)
	self.actionBigBlind(bbPlayer)

	log.Debug("下小盲注: %v %v", sbPlayer.str(), self.smallBlindSeat)
	log.Debug("下大盲注: %v %v", bbPlayer.str(), self.bigBlindSeat)
}

// 检查玩家金钱，如果不足的话，就直接购买筹码，再不足的话踢出座位
func (self *Room) checkMoney() {
	for i := 0; i < MAX_SEAT_COUNT; i ++ {
		player := self.playersInSeat[i]
		if player != nil && player.money < self.minMoney && !player.autoReBuy {
			self.playersInSeat[i] = nil
			self.broadcastStandUp(player.seat)
			log.Debug("%v 因为没有足够的筹码被踢出 %v", player.str(), player.money)
		}
	}
}

// 开始回合
func (self *Room) beginTurn() {
	// 小于最小的开场人数，不能开始比赛
	if self.getPlayerInSeatCount() < self.minCount {
		self.reset()
		self.round = message.PokerRound_ROUND_NONE
		self.broadcastRound()
		return
	}

	// 洗牌
	self.deck = hand.NewDealer().Deck()

	// 重置玩家数据
	for _, v := range self.playersInSeat {
		if v != nil && v.state != message.PlayerState_STATE_STAND {
			v.beginTurn()
		}
	}

	// 通知客户端开启新的一局
	self.round = message.PokerRound_ROUND_START
	self.broadcastRound()

	// 清理上一局的数据
	self.board = [MAX_BOARD_COUNT]*hand.Card{}
	self.pots = []*Pot{&Pot{value:0}}
	self.bets = make(map[int]int)

	// 选定庄家
	self.updateDealer()

	// 下盲注
	self.updateBlindAnte()

	// 设置已经开始比赛的标识
	self.isPlaying = true

	log.Debug("牌局初始化完毕")

	// 一秒钟后开始发牌
	utils.Timer(1, func() {
		self.processPreflop()
	})
}

// 此局结束  清理要移除的玩家
func (self *Room) endTurn() {
	log.Debug("牌局结束")

	// 检查金钱，移除没钱的玩家
	self.checkMoney()
	self.isPlaying = false

	// 将所有玩家的状态置为准备
	for _, v := range self.playersInSeat {
		if v != nil {
			v.state = message.PlayerState_STATE_READY
		}
	}

	// 三秒钟之后开始新局
	utils.Timer(3, func() {
		self.beginTurn()
	})
}

// 回合是否结束
func (self *Room) isRoundFinished() bool {
	// 当只有一个玩家没弃牌的时候，回合直接结束
	if len(self.playersNotFold()) < 2 {
		log.Debug("只有一个玩家了，牌局结束")
		return true
	}

	if len(self.playersPlaying()) < 1 {
		log.Debug("所有玩家都all-in或者弃牌了，牌局结束")
		return true
	}

	//	# 当所有的押注都相等的时候，回合结束，否则只要有人加注，回合一直进行下去
	//	# 但是要注意，必须一轮都走完才能开始判断是否相等，否则要必须每个人都下注才行
	return !self.firstBettingPass && self.betsEqual()
}

// 每回合开始的时候做一些清理
func (self *Room) onRoundBegin() {
	log.Debug("新回合: %v", self.round)
	self.firstBettingPass = true
	self.position = -1    // 重置当前行动玩家的座位
	self.lastRaise = 0    // 每回合重置加注数据

	if self.round != message.PokerRound_ROUND_PRELOP {
		self.bets = map[int]int{}    // 清理玩家押注
	}

	if self.round == message.PokerRound_ROUND_PRELOP {
		if len(self.playersInGame()) == 2 {
			// 如果只有两个人的话，则庄家先行动
			self.position = self.dealerSeat
		} else {
			// 大盲注的下一个为枪口位 此回合枪口位先行动
			self.position = self.bigBlindSeat
		}
		// 大盲注最后一个行动
		self.lastToTalkSeat = self.bigBlindSeat
	} else if self.round == message.PokerRound_ROUND_FLOP || self.round == message.PokerRound_ROUND_TURN || self.round == message.PokerRound_ROUND_RIVER {
		// 这几个回合庄家的下一个先行动
		self.position = self.dealerSeat

		// 庄家最后行动，如果庄家弃牌了，则庄家的前一个玩家最后行动
		dealer := self.getPlayerBySeat(self.dealerSeat)
		if dealer != nil {
			self.lastToTalkSeat = self.dealerSeat
		} else {
			self.lastToTalkSeat = self.getPrevPosition(self.dealerSeat, nil)
		}
	}

	log.Debug("回合开始:  %v  %v", self.dealerSeat, self.position)
}

// 处理下一回合
func (self *Room) nextRound() {
	self.position = -1
	switch self.round {
	case message.PokerRound_ROUND_START:
		self.processPreflop()
	case message.PokerRound_ROUND_PRELOP:
		self.processFlop()
	case message.PokerRound_ROUND_FLOP:
		self.processTurn()
	case message.PokerRound_ROUND_TURN:
		self.processRiver()
	case message.PokerRound_ROUND_RIVER:
		self.processPostRiver()
	}
}

// 下大小盲注 轮流压注
func (self *Room) processPreflop() {
	log.Debug("processPreflop")
	self.round = message.PokerRound_ROUND_PRELOP
	self.onRoundBegin()
	self.broadcastRound()

	// 每个玩家发两张手牌
	for _, player := range self.playersInGame() {
		player.handCard1 = self.deck.Pop()
		player.handCard2 = self.deck.Pop()
		player.SendMsg(message.MSG_HAND_CARD, &message.S2C_HandCard{
			HandCard1:proto.Int(player.handCard1.Index()),
			HandCard2:proto.Int(player.handCard2.Index()),
		})
	}

	// 开始玩家处理(叫注)
	self.nextPlayer()
}

// 翻牌，发三张牌，轮流压注
func (self *Room) processFlop() {
	log.Debug("processFlop")
	self.round = message.PokerRound_ROUND_FLOP
	self.onRoundBegin()

	self.board[0] = self.deck.Pop()
	self.board[1] = self.deck.Pop()
	self.board[2] = self.deck.Pop()

	self.broadcastRound(self.board[0], self.board[1], self.board[2])
	self.broadcastCardType()
	self.nextPlayer()
}

// 转牌，发一张牌，轮流压注
func (self *Room) processTurn() {
	log.Debug("processTurn")
	self.round = message.PokerRound_ROUND_TURN
	self.onRoundBegin()
	self.board[3] = self.deck.Pop()

	self.broadcastRound(self.board[3])
	self.broadcastCardType()
	self.nextPlayer()
}

// 河牌，发一张牌，轮流压注
func (self *Room) processRiver() {
	log.Debug("processRiver")
	self.round = message.PokerRound_ROUND_RIVER
	self.onRoundBegin()
	self.board[4] = self.deck.Pop()

	self.broadcastRound(self.board[4])
	self.broadcastCardType()
	self.nextPlayer()
}

// 河牌之后比较大小 弃牌的玩家可以封牌（不让其他玩家看到自己的牌），最后一局的玩家必须亮牌，all-in的玩家必须亮牌
func (self *Room) processPostRiver() {
	log.Debug("processPostRiver")
	self.round = message.PokerRound_ROUND_POST_RIVER
	self.broadcastRound()

	//	# 玩家亮牌 TODO 在分配奖池环节才会判定玩家胜负，如果先亮牌则只能处理为所有没弃牌的玩家都亮牌
	//	# 实际比赛中确实应该先亮牌，不过是按照一定顺序亮牌，而且认定为输的人可以不亮牌，只有all-in和赢得奖池的人才必须亮牌
	self.updateShowdown()

	// 分配奖池
	self.distributePot()

	// 本轮游戏结束
	self.endTurn()
}

// 未弃牌玩家的最大押注(包含all-in的)
func (self *Room) highestBetNotFold() int {
	players := self.playersNotFold()
	maxBet := 0
	for _, player := range players {
		bet := self.getBet(player)
		if bet > maxBet {
			maxBet = bet
		}
	}
	return maxBet
}

// 场上玩家的最大押注(不包含all-in的和弃牌的)
func (self *Room) highestBetPlaying() int {
	players := self.playersPlaying()
	maxBet := 0
	for _, player := range players {
		bet := self.getBet(player)
		if bet > maxBet {
			maxBet = bet
		}
	}
	return maxBet
}

// 所有押注金额相等（回合结束的判定条件之一）
func (self *Room) betsEqual() bool {
	if self.highestBetNotFold() > self.highestBetPlaying() {
		//		# 如果all-in的押注比其他人高，不算相等，其他人必须加注或者跟注
		//	# all-in的押注可以比其他人低
		return false
	}

	// 如果场上能行动的玩家的押注不相等，也不算相等
	players := self.playersPlaying()
	bet := self.getBet(players[0])
	for _, player := range players {
		if bet != self.getBet(player) {
			return false
		}
	}
	return true
}
